package net.midnighttd.game;

import net.midnighttd.engine.Engine;
import net.midnighttd.engine.entity.Entity;
import net.midnighttd.engine.entity.TriggerListener;
import net.midnighttd.engine.entity.EntityExistanceListener;
import net.midnighttd.engine.view.sprite.Sprite;
import net.midnighttd.engine.view.sprite.MovementStateListener;
import net.midnighttd.engine.view.sprite.MovementState;
import net.midnighttd.engine.view.sprite.Movement;
import net.midnighttd.game.entity.Unit;
import net.midnighttd.game.entity.Tower;
import net.midnighttd.game.entity.EntityFactory;
import java.util.LinkedList;
import java.awt.*;
import org.w3c.dom.NodeList;
import org.w3c.dom.Node;
import org.w3c.dom.Element;

/**
 * Author: Adam Scarr
 * Date: 22/04/2009
 * Time: 7:36:46 PM
 */
public class MidnightTD extends Engine implements EntityExistanceListener, TriggerListener, MovementStateListener {
    private LinkedList<Spawn> spawns = new LinkedList<Spawn>();
    private LinkedList<StateChangeListener> stateChangeListeners = new LinkedList<StateChangeListener>();
    private int money, startingMoney;
    private int lives, startingLives;
    private boolean gameOver = false;

    public MidnightTD() {
        getEntityManager().addEntityExistanceListener(this);
        EntityFactory e = new EntityFactory();
        getEntityManager().addEntityFactory("unit", e);
        getEntityManager().addEntityFactory("tower", e);
        getEntityManager().addEntityFactory("upgrade", e);
    }

    public void loadFromXML(Element e) {
        super.loadFromXML(e);
        
        money = Integer.valueOf(e.getAttribute("money"));
        startingMoney = money;
        lives = Integer.valueOf(e.getAttribute("lives"));
        startingLives = lives;
        loadSpawns(e.getElementsByTagName("spawn"));
    }

    public void reset() {
        startSpawns();
        gameOver = false;
        money = startingMoney;
        lives = startingLives;
        notifyStateChange(GameState.LIVES_CHANGED);
    }

    public void gameLoop() {
        super.gameLoop();

        for(Spawn s: spawns) {
            LinkedList<Entity> wave = s.getSpawn();
            for(Entity ent: wave) {
                ent.setActive(true);
            }
        }
    }

    public void trigger(Entity e) {
        if(e.getType().equals("unit")) {
            Unit u = (Unit)e;
            lives--;
            getEntityManager().removeActiveEnt(u);
            notifyStateChange(GameState.LIVES_CHANGED);
            if(lives <= 0) {
                stopSpawns();
                getEntityManager().purgeActiveEnts();
                gameOver = true;
                notifyStateChange(GameState.GAME_OVER);
            }
        }
    }

    private void loadSpawns(NodeList spawns) {
        for(int i = 0; i < spawns.getLength(); i++) {
            if(spawns.item(i).getNodeType() != Node.ELEMENT_NODE) continue;
            Element spawn = (Element)spawns.item(i);

            Spawn s = new Spawn(this, spawn);
            s.startSpawning();

            getEntityManager().addTriggerListener(s.getEnd().x, s.getEnd().y, this);

            this.spawns.add(s);
        }
    }

    public void stopSpawns() {
        for(Spawn spawn: spawns) {
            spawn.stopSpawning();
        }
    }

    private void startSpawns() {
         for(Spawn spawn: spawns) {
            spawn.startSpawning();
        }
    }

    private synchronized void notifyStateChange(GameState change) {
        for(StateChangeListener l: new LinkedList<StateChangeListener>(stateChangeListeners)) {
            l.stateChanged(change);
        }
    }

    public synchronized void addStateChangeListener(StateChangeListener l) {
        stateChangeListeners.add(l);
    }

    public boolean isOver() {
        return gameOver;
    }

    public int getMoney() {
        return money;
    }

    public int getLives() {
        return lives;
    }

    public void entityCreated(Entity e) {
        if(e.getType().equals("tower")) {
            Tower t = (Tower)e;

            money -= t.getCost();
            notifyStateChange(GameState.MONEY_CHANGED);
        }
    }

    public void entityDeleted(Entity e) {
        if(e.getType().equals("unit")) {
            Unit u = (Unit)e;
            money += u.getBounty();
            notifyStateChange(GameState.MONEY_CHANGED);

            Sprite s = getSpriteManager().getSprite("+" + u.getBounty());
            Dimension tile = getMapManager().getTileSize();
            s.setLocation(u.getX() * tile.width, u.getY() * tile.height);
            s.moveBy(0, -10, 10);
            s.addMovementStateListener(this);
        }
    }

    public void movementStateChanged(Sprite sprite, MovementState state, Movement movement) {
        if(state == MovementState.end) {
            getSpriteManager().remove(sprite);
        }
    }
}
